knitr::opts_knit$set(root.dir = "/Users/amitmeir/Documents/rglab/flowReMix")

Loading Data

library(flowReMix)
getExpression <- function(str) {
  first <- substr(str, 1, 7)
  second <- substr(str, 8, nchar(str))
  second <- strsplit(second, "")[[1]]
  seperators <- c(0, which(second %in% c("-", "+")))
  expressed <- list()
  for(i in 2:length(seperators)) {
    if(second[seperators[i]] == "+") {
      expressed[[i]] <- paste(second[(seperators[(i - 1)] + 1) : seperators[i]], collapse = '')
    }
  }
  expressed <- paste(unlist(expressed), collapse = '')
  expressed <- paste(first, expressed, sep = '')
  return(expressed)
}
# Loading Data --------------------------------
# hvtn <- read.csv(file = "data/merged_505_stats.csv")
# names(hvtn) <- tolower(names(hvtn))
# hvtn <- subset(hvtn, !is.na(ptid))
# saveRDS(hvtn, file = "data/505_stats.rds")
# Getting Demographic data ------------------------
demo <- read.csv(file = "data/primary505.csv")
infect <- data.frame(ptid = demo$ptid, status = demo$HIVwk28preunbl)
infect <- subset(infect, infect$ptid %in% hvtn$ptid)
# Getting marginals -----------------------------
library(flowReMix)
hvtn <- readRDS(file = "data/505_stats.rds")
length(unique(hvtn$name))
length(unique(hvtn$ptid))
length(unique(hvtn$population))
unique(hvtn$population)
unique(hvtn$stim)
nchars <- nchar(as.character(unique(hvtn$population)))
#marginals <- unique(hvtn$population)[nchars < 26]
marginals <- unique(hvtn$population)[nchars == 26]
marginals <- subset(hvtn, population %in% marginals)
marginals <- subset(marginals, stim %in% c("negctrl", "VRC ENV A",
                                           "VRC ENV B", "VRC ENV C",
                                           "VRC GAG B", "VRC NEF B",
                                           "VRC POL 1 B", "VRC POL 2 B"))
marginals <- subset(marginals, !(population %in% c("4+", "8+")))
marginals <- subset(marginals, !(population %in% c("8+/107a-154-IFNg-IL2-TNFa-", "4+/107a-154-IFNg-IL2-TNFa-")))
marginals$stim <- factor(as.character(marginals$stim))
marginals$population <- factor(as.character(marginals$population))
# Descriptives -------------------------------------
library(ggplot2)
marginals$prop <- marginals$count / marginals$parentcount
# ggplot(marginals) + geom_boxplot(aes(x = population, y = log(prop), col = stim))
require(dplyr)
negctrl <- subset(marginals, stim == "negctrl")
negctrl <- summarize(group_by(negctrl, ptid, population), negprop = mean(prop))
negctrl <- as.data.frame(negctrl)
marginals <- merge(marginals, negctrl, all.x = TRUE)
# ggplot(subset(marginals, stim != "negctrl" & parent == "4+")) +
#   geom_point(aes(x = log(negprop), y = log(prop)), size = 0.25) +
#   facet_grid(stim ~ population, scales = "free") +
#   theme_bw() +
#   geom_abline(intercept = 0, slope = 1)
# Setting up data for analysis ---------------------------
unique(marginals$stim)
gag <- subset(marginals, stim %in% c("VRC GAG B", "negctrl"))
gag$subset <- factor(paste("gag", gag$population, sep = "/"))
gag$stimGroup <- "gag"
pol <-subset(marginals, stim %in% c("negctrl", "VRC POL 1 B", "VRC POL 2 B"))
pol$subset <- factor(paste("pol", pol$population, sep = "/"))
pol$stimGroup <- "pol"
env <- subset(marginals, stim %in% c("negctrl", "VRC ENV C", "VRC ENV B", "VRC ENV A"))
env$subset <- factor(paste("env", env$population, sep = "/"))
env$stimGroup <- "env"
nef <- subset(marginals, stim %in% c("negctrl", "VRC NEF B"))
nef$subset <- factor(paste("nef", nef$population, sep = "/"))
nef$stimGroup <- "nef"
subsetDat <- rbind(gag, pol, env, nef)
subsetDat$stim <- as.character(subsetDat$stim)
subsetDat$stim[subsetDat$stim == "negctrl"] <- 0
subsetDat$stim <- factor(subsetDat$stim)
# Converting subset names ------------------
subsets <- as.character(unique(subsetDat$subset))
expressed <- sapply(subsets, getExpression)
map <- cbind(subsets, expressed)
subsetDat$subset <- as.character(subsetDat$subset)
for(i in 1:nrow(map)) {
  subsetDat$subset[which(subsetDat$subset == map[i, 1])] <- map[i, 2]
}
subsetDat$subset <- factor(subsetDat$subset)
# Getting outcomes -------------------------------
treatmentdat <- read.csv(file = "data/rx_v2.csv")
names(treatmentdat) <- tolower(names(treatmentdat))
treatmentdat$ptid <- factor(gsub("-", "", (treatmentdat$ptid)))
treatmentdat <- subset(treatmentdat, ptid %in% unique(subsetDat$ptid))
# Finding problematic subsets?
keep <- by(subsetDat, list(subsetDat$subset), function(x) mean(x$count > 1) > 0.02)
keep <- names(keep[sapply(keep, function(x) x)])
#result$subsets[result$qvals < 0.1] %in% keep
subsetDat <- subset(subsetDat, subset %in% keep)

Loading Model

load(file = "Data Analysis/results/HVTNclust2.Robj")
Warning in (function (..., list = character(), pos = -1, envir = as.environment(pos),  :
  object 'print.htmlwidget' not found
Warning in (function (..., list = character(), pos = -1, envir = as.environment(pos),  :
  object 'print.html' not found
Warning in (function (..., list = character(), pos = -1, envir = as.environment(pos),  :
  object 'print.shiny.tag' not found
Warning in (function (..., list = character(), pos = -1, envir = as.environment(pos),  :
  object 'print.shiny.tag.list' not found
Warning in (function (..., list = character(), pos = -1, envir = as.environment(pos),  :
  object 'print.knit_asis' not found
Warning in (function (..., list = character(), pos = -1, envir = as.environment(pos),  :
  object 'print.knit_image_paths' not found

ROC Table for Vaccination

ROC Table for Infection

vaccine <- outcome[, 2] == 0
hiv <- infect[, 2]
hiv[vaccine == 0] <- NA
infectROC <- rocTable(fit, hiv, direction = ">", adjust = "BH",
                      sortAUC = FALSE)
infectROC[order(infectROC$auc, decreasing = TRUE), ]

Scatter Plot: Figure too larget to fit here…

scatter <- plot(fit, target = vaccine, type = "scatter", ncol = 11)

FDR Curves: Figure too larget to fit here…

vaccination <- outcome[, 2] == 0
fdrplot <- plot(fit, target = vaccination, type = "FDR")

Functionality and Polyfunctionality Boxplots

nfunctions <- sapply(strsplit(colnames(fit$posteriors)[-1], "+", fixed = TRUE), function(x) length(x) - 1)
weightList <- list()
weightList$polyfunctionality <- weights <- nfunctions / choose(5, nfunctions)
weightList$functionality <- rep(1, length(nfunctions))

subsets <- names(fit$posteriors[, -1])
stim <- sapply(strsplit(subsets, "/"), function(x) x[1])
stimnames <- unique(stim)
stim <- lapply(stimnames, function(x) subsets[stim %in% x])
names(stim) <- stimnames
parent <- sapply(strsplit(subsets, "/"), function(x) x[2])
parentnames <- unique(parent)
parent <- lapply(parentnames, function(x) subsets[parent %in% x])
names(parent) <- parentnames
stimparent  <- sapply(strsplit(subsets, "/"), function(x) paste(x[1:2], collapse = "/"))
stimparentnames <-unique(stimparent)
stimparent <- lapply(stimparentnames, function(x) subsets[stimparent %in% x])
names(stimparent) <- stimparentnames

infection <- hiv
infection[hiv == 0] <- "NON-INFECTED"
infection[hiv == 1] <- "INFECTED"
infection[is.na(hiv)] <- "PLACEBO"
plot(fit, type = "boxplot", groups = stim, weights = weightList, ncol = 2,
     target = infection)
plot(fit, type = "boxplot", groups = parent, weights = weightList, ncol = 2,
                  target = infection)
plot(fit, type = "boxplot", groups = stimparent, weights = weightList, ncol = 3, target = infection)

Random effect model for differnt thresholds

load("data analysis/results/HVTNrand2.Robj")
for(threshold in c(0.5, 0.75, 0.85, 0.9, 0.95, 1)) {
  randplot <- plot(randStability, fill = rocResults$auc,
                  threshold = threshold)
  print(randplot)
}

Ising model for differnt thresholds

load("data analysis/results/HVTNising2.Robj")
for(threshold in c(0.5, 0.75, 0.85, 0.9, 0.95, 1)) {
  isingplot <- plot(stability, fill = rocResults$auc, threshold = threshold)
  print(isingplot)
}

LS0tCnRpdGxlOiAiUlYxNDQgYW5hbHlzaXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKYGBge3IgInNldHVwIiwgaW5jbHVkZT1UUlVFLCB3YXJuaW5nPUZBTFNFfQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICIvVXNlcnMvYW1pdG1laXIvRG9jdW1lbnRzL3JnbGFiL2Zsb3dSZU1peCIpCmBgYAoKKipMb2FkaW5nIERhdGEqKgoKYGBge3IsIHJlc3VsdHMgPSAiaGlkZSIsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZmxvd1JlTWl4KQpnZXRFeHByZXNzaW9uIDwtIGZ1bmN0aW9uKHN0cikgewogIGZpcnN0IDwtIHN1YnN0cihzdHIsIDEsIDcpCiAgc2Vjb25kIDwtIHN1YnN0cihzdHIsIDgsIG5jaGFyKHN0cikpCiAgc2Vjb25kIDwtIHN0cnNwbGl0KHNlY29uZCwgIiIpW1sxXV0KICBzZXBlcmF0b3JzIDwtIGMoMCwgd2hpY2goc2Vjb25kICVpbiUgYygiLSIsICIrIikpKQogIGV4cHJlc3NlZCA8LSBsaXN0KCkKICBmb3IoaSBpbiAyOmxlbmd0aChzZXBlcmF0b3JzKSkgewogICAgaWYoc2Vjb25kW3NlcGVyYXRvcnNbaV1dID09ICIrIikgewogICAgICBleHByZXNzZWRbW2ldXSA8LSBwYXN0ZShzZWNvbmRbKHNlcGVyYXRvcnNbKGkgLSAxKV0gKyAxKSA6IHNlcGVyYXRvcnNbaV1dLCBjb2xsYXBzZSA9ICcnKQogICAgfQogIH0KCiAgZXhwcmVzc2VkIDwtIHBhc3RlKHVubGlzdChleHByZXNzZWQpLCBjb2xsYXBzZSA9ICcnKQogIGV4cHJlc3NlZCA8LSBwYXN0ZShmaXJzdCwgZXhwcmVzc2VkLCBzZXAgPSAnJykKICByZXR1cm4oZXhwcmVzc2VkKQp9CgojIExvYWRpbmcgRGF0YSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIGh2dG4gPC0gcmVhZC5jc3YoZmlsZSA9ICJkYXRhL21lcmdlZF81MDVfc3RhdHMuY3N2IikKIyBuYW1lcyhodnRuKSA8LSB0b2xvd2VyKG5hbWVzKGh2dG4pKQojIGh2dG4gPC0gc3Vic2V0KGh2dG4sICFpcy5uYShwdGlkKSkKIyBzYXZlUkRTKGh2dG4sIGZpbGUgPSAiZGF0YS81MDVfc3RhdHMucmRzIikKCgojIEdldHRpbmcgRGVtb2dyYXBoaWMgZGF0YSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KZGVtbyA8LSByZWFkLmNzdihmaWxlID0gImRhdGEvcHJpbWFyeTUwNS5jc3YiKQppbmZlY3QgPC0gZGF0YS5mcmFtZShwdGlkID0gZGVtbyRwdGlkLCBzdGF0dXMgPSBkZW1vJEhJVndrMjhwcmV1bmJsKQppbmZlY3QgPC0gc3Vic2V0KGluZmVjdCwgaW5mZWN0JHB0aWQgJWluJSBodnRuJHB0aWQpCgojIEdldHRpbmcgbWFyZ2luYWxzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmxpYnJhcnkoZmxvd1JlTWl4KQpodnRuIDwtIHJlYWRSRFMoZmlsZSA9ICJkYXRhLzUwNV9zdGF0cy5yZHMiKQpsZW5ndGgodW5pcXVlKGh2dG4kbmFtZSkpCmxlbmd0aCh1bmlxdWUoaHZ0biRwdGlkKSkKbGVuZ3RoKHVuaXF1ZShodnRuJHBvcHVsYXRpb24pKQp1bmlxdWUoaHZ0biRwb3B1bGF0aW9uKQp1bmlxdWUoaHZ0biRzdGltKQpuY2hhcnMgPC0gbmNoYXIoYXMuY2hhcmFjdGVyKHVuaXF1ZShodnRuJHBvcHVsYXRpb24pKSkKI21hcmdpbmFscyA8LSB1bmlxdWUoaHZ0biRwb3B1bGF0aW9uKVtuY2hhcnMgPCAyNl0KbWFyZ2luYWxzIDwtIHVuaXF1ZShodnRuJHBvcHVsYXRpb24pW25jaGFycyA9PSAyNl0KbWFyZ2luYWxzIDwtIHN1YnNldChodnRuLCBwb3B1bGF0aW9uICVpbiUgbWFyZ2luYWxzKQptYXJnaW5hbHMgPC0gc3Vic2V0KG1hcmdpbmFscywgc3RpbSAlaW4lIGMoIm5lZ2N0cmwiLCAiVlJDIEVOViBBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWUkMgRU5WIEIiLCAiVlJDIEVOViBDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWUkMgR0FHIEIiLCAiVlJDIE5FRiBCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWUkMgUE9MIDEgQiIsICJWUkMgUE9MIDIgQiIpKQptYXJnaW5hbHMgPC0gc3Vic2V0KG1hcmdpbmFscywgIShwb3B1bGF0aW9uICVpbiUgYygiNCsiLCAiOCsiKSkpCm1hcmdpbmFscyA8LSBzdWJzZXQobWFyZ2luYWxzLCAhKHBvcHVsYXRpb24gJWluJSBjKCI4Ky8xMDdhLTE1NC1JRk5nLUlMMi1UTkZhLSIsICI0Ky8xMDdhLTE1NC1JRk5nLUlMMi1UTkZhLSIpKSkKbWFyZ2luYWxzJHN0aW0gPC0gZmFjdG9yKGFzLmNoYXJhY3RlcihtYXJnaW5hbHMkc3RpbSkpCm1hcmdpbmFscyRwb3B1bGF0aW9uIDwtIGZhY3Rvcihhcy5jaGFyYWN0ZXIobWFyZ2luYWxzJHBvcHVsYXRpb24pKQoKIyBEZXNjcmlwdGl2ZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpsaWJyYXJ5KGdncGxvdDIpCm1hcmdpbmFscyRwcm9wIDwtIG1hcmdpbmFscyRjb3VudCAvIG1hcmdpbmFscyRwYXJlbnRjb3VudAojIGdncGxvdChtYXJnaW5hbHMpICsgZ2VvbV9ib3hwbG90KGFlcyh4ID0gcG9wdWxhdGlvbiwgeSA9IGxvZyhwcm9wKSwgY29sID0gc3RpbSkpCgpyZXF1aXJlKGRwbHlyKQpuZWdjdHJsIDwtIHN1YnNldChtYXJnaW5hbHMsIHN0aW0gPT0gIm5lZ2N0cmwiKQpuZWdjdHJsIDwtIHN1bW1hcml6ZShncm91cF9ieShuZWdjdHJsLCBwdGlkLCBwb3B1bGF0aW9uKSwgbmVncHJvcCA9IG1lYW4ocHJvcCkpCm5lZ2N0cmwgPC0gYXMuZGF0YS5mcmFtZShuZWdjdHJsKQptYXJnaW5hbHMgPC0gbWVyZ2UobWFyZ2luYWxzLCBuZWdjdHJsLCBhbGwueCA9IFRSVUUpCgojIGdncGxvdChzdWJzZXQobWFyZ2luYWxzLCBzdGltICE9ICJuZWdjdHJsIiAmIHBhcmVudCA9PSAiNCsiKSkgKwojICAgZ2VvbV9wb2ludChhZXMoeCA9IGxvZyhuZWdwcm9wKSwgeSA9IGxvZyhwcm9wKSksIHNpemUgPSAwLjI1KSArCiMgICBmYWNldF9ncmlkKHN0aW0gfiBwb3B1bGF0aW9uLCBzY2FsZXMgPSAiZnJlZSIpICsKIyAgIHRoZW1lX2J3KCkgKwojICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKQoKIyBTZXR0aW5nIHVwIGRhdGEgZm9yIGFuYWx5c2lzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp1bmlxdWUobWFyZ2luYWxzJHN0aW0pCmdhZyA8LSBzdWJzZXQobWFyZ2luYWxzLCBzdGltICVpbiUgYygiVlJDIEdBRyBCIiwgIm5lZ2N0cmwiKSkKZ2FnJHN1YnNldCA8LSBmYWN0b3IocGFzdGUoImdhZyIsIGdhZyRwb3B1bGF0aW9uLCBzZXAgPSAiLyIpKQpnYWckc3RpbUdyb3VwIDwtICJnYWciCnBvbCA8LXN1YnNldChtYXJnaW5hbHMsIHN0aW0gJWluJSBjKCJuZWdjdHJsIiwgIlZSQyBQT0wgMSBCIiwgIlZSQyBQT0wgMiBCIikpCnBvbCRzdWJzZXQgPC0gZmFjdG9yKHBhc3RlKCJwb2wiLCBwb2wkcG9wdWxhdGlvbiwgc2VwID0gIi8iKSkKcG9sJHN0aW1Hcm91cCA8LSAicG9sIgplbnYgPC0gc3Vic2V0KG1hcmdpbmFscywgc3RpbSAlaW4lIGMoIm5lZ2N0cmwiLCAiVlJDIEVOViBDIiwgIlZSQyBFTlYgQiIsICJWUkMgRU5WIEEiKSkKZW52JHN1YnNldCA8LSBmYWN0b3IocGFzdGUoImVudiIsIGVudiRwb3B1bGF0aW9uLCBzZXAgPSAiLyIpKQplbnYkc3RpbUdyb3VwIDwtICJlbnYiCm5lZiA8LSBzdWJzZXQobWFyZ2luYWxzLCBzdGltICVpbiUgYygibmVnY3RybCIsICJWUkMgTkVGIEIiKSkKbmVmJHN1YnNldCA8LSBmYWN0b3IocGFzdGUoIm5lZiIsIG5lZiRwb3B1bGF0aW9uLCBzZXAgPSAiLyIpKQpuZWYkc3RpbUdyb3VwIDwtICJuZWYiCnN1YnNldERhdCA8LSByYmluZChnYWcsIHBvbCwgZW52LCBuZWYpCnN1YnNldERhdCRzdGltIDwtIGFzLmNoYXJhY3RlcihzdWJzZXREYXQkc3RpbSkKc3Vic2V0RGF0JHN0aW1bc3Vic2V0RGF0JHN0aW0gPT0gIm5lZ2N0cmwiXSA8LSAwCnN1YnNldERhdCRzdGltIDwtIGZhY3RvcihzdWJzZXREYXQkc3RpbSkKCiMgQ29udmVydGluZyBzdWJzZXQgbmFtZXMgLS0tLS0tLS0tLS0tLS0tLS0tCnN1YnNldHMgPC0gYXMuY2hhcmFjdGVyKHVuaXF1ZShzdWJzZXREYXQkc3Vic2V0KSkKZXhwcmVzc2VkIDwtIHNhcHBseShzdWJzZXRzLCBnZXRFeHByZXNzaW9uKQptYXAgPC0gY2JpbmQoc3Vic2V0cywgZXhwcmVzc2VkKQpzdWJzZXREYXQkc3Vic2V0IDwtIGFzLmNoYXJhY3RlcihzdWJzZXREYXQkc3Vic2V0KQpmb3IoaSBpbiAxOm5yb3cobWFwKSkgewogIHN1YnNldERhdCRzdWJzZXRbd2hpY2goc3Vic2V0RGF0JHN1YnNldCA9PSBtYXBbaSwgMV0pXSA8LSBtYXBbaSwgMl0KfQpzdWJzZXREYXQkc3Vic2V0IDwtIGZhY3RvcihzdWJzZXREYXQkc3Vic2V0KQoKIyBHZXR0aW5nIG91dGNvbWVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KdHJlYXRtZW50ZGF0IDwtIHJlYWQuY3N2KGZpbGUgPSAiZGF0YS9yeF92Mi5jc3YiKQpuYW1lcyh0cmVhdG1lbnRkYXQpIDwtIHRvbG93ZXIobmFtZXModHJlYXRtZW50ZGF0KSkKdHJlYXRtZW50ZGF0JHB0aWQgPC0gZmFjdG9yKGdzdWIoIi0iLCAiIiwgKHRyZWF0bWVudGRhdCRwdGlkKSkpCnRyZWF0bWVudGRhdCA8LSBzdWJzZXQodHJlYXRtZW50ZGF0LCBwdGlkICVpbiUgdW5pcXVlKHN1YnNldERhdCRwdGlkKSkKCiMgRmluZGluZyBwcm9ibGVtYXRpYyBzdWJzZXRzPwprZWVwIDwtIGJ5KHN1YnNldERhdCwgbGlzdChzdWJzZXREYXQkc3Vic2V0KSwgZnVuY3Rpb24oeCkgbWVhbih4JGNvdW50ID4gMSkgPiAwLjAyKQprZWVwIDwtIG5hbWVzKGtlZXBbc2FwcGx5KGtlZXAsIGZ1bmN0aW9uKHgpIHgpXSkKI3Jlc3VsdCRzdWJzZXRzW3Jlc3VsdCRxdmFscyA8IDAuMV0gJWluJSBrZWVwCnN1YnNldERhdCA8LSBzdWJzZXQoc3Vic2V0RGF0LCBzdWJzZXQgJWluJSBrZWVwKQpzdWJzZXREYXQkc3Vic2V0IDwtIGZhY3Rvcihhcy5jaGFyYWN0ZXIoc3Vic2V0RGF0JHN1YnNldCkpCmBgYAoKKipMb2FkaW5nIE1vZGVsKioKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQpsb2FkKGZpbGUgPSAiRGF0YSBBbmFseXNpcy9yZXN1bHRzL0hWVE5jbHVzdDIuUm9iaiIpCmBgYAoKKipST0MgVGFibGUgZm9yIFZhY2NpbmF0aW9uKioKYGBge3Isd2FybmluZz1GQUxTRX0KcmVxdWlyZShwUk9DKQpvdXRjb21lIDwtIHRyZWF0bWVudGRhdFssIGMoMTMsIDE1KV0Kcm9jUmVzdWx0cyA8LSByb2NUYWJsZShmaXQsIG91dGNvbWVbLCAyXSwgZGlyZWN0aW9uID0gIj4iLCBhZGp1c3QgPSAiQkgiLAogICAgICAgICAgICAgICAgICAgICAgIHNvcnRBVUMgPSBGQUxTRSkKcm9jUmVzdWx0c1tvcmRlcihyb2NSZXN1bHRzJGF1YywgZGVjcmVhc2luZyA9IFRSVUUpLCBdCmBgYAoKKipST0MgVGFibGUgZm9yIEluZmVjdGlvbioqCmBgYHtyLHdhcm5pbmc9RkFMU0V9CnZhY2NpbmUgPC0gb3V0Y29tZVssIDJdID09IDAKaGl2IDwtIGluZmVjdFssIDJdCmhpdlt2YWNjaW5lID09IDBdIDwtIE5BCmluZmVjdFJPQyA8LSByb2NUYWJsZShmaXQsIGhpdiwgZGlyZWN0aW9uID0gIj4iLCBhZGp1c3QgPSAiQkgiLAogICAgICAgICAgICAgICAgICAgICAgc29ydEFVQyA9IEZBTFNFKQppbmZlY3RST0Nbb3JkZXIoaW5mZWN0Uk9DJGF1YywgZGVjcmVhc2luZyA9IFRSVUUpLCBdCmBgYAoKKipTY2F0dGVyIFBsb3QqKjogRmlndXJlIHRvbyBsYXJnZXQgdG8gZml0IGhlcmUuLi4KYGBge3IsIGV2YWwgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQpzY2F0dGVyIDwtIHBsb3QoZml0LCB0YXJnZXQgPSB2YWNjaW5lLCB0eXBlID0gInNjYXR0ZXIiLCBuY29sID0gMTEpCmBgYAoKKipGRFIgQ3VydmVzKio6IEZpZ3VyZSB0b28gbGFyZ2V0IHRvIGZpdCBoZXJlLi4uCmBgYHtyLHdhcm5pbmc9RkFMU0V9CnZhY2NpbmF0aW9uIDwtIG91dGNvbWVbLCAyXSA9PSAwCmZkcnBsb3QgPC0gcGxvdChmaXQsIHRhcmdldCA9IHZhY2NpbmF0aW9uLCB0eXBlID0gIkZEUiIpCmBgYAoKCioqRnVuY3Rpb25hbGl0eSBhbmQgUG9seWZ1bmN0aW9uYWxpdHkgQm94cGxvdHMqKgpgYGB7cix3YXJuaW5nPUZBTFNFfQpuZnVuY3Rpb25zIDwtIHNhcHBseShzdHJzcGxpdChjb2xuYW1lcyhmaXQkcG9zdGVyaW9ycylbLTFdLCAiKyIsIGZpeGVkID0gVFJVRSksIGZ1bmN0aW9uKHgpIGxlbmd0aCh4KSAtIDEpCndlaWdodExpc3QgPC0gbGlzdCgpCndlaWdodExpc3QkcG9seWZ1bmN0aW9uYWxpdHkgPC0gd2VpZ2h0cyA8LSBuZnVuY3Rpb25zIC8gY2hvb3NlKDUsIG5mdW5jdGlvbnMpCndlaWdodExpc3QkZnVuY3Rpb25hbGl0eSA8LSByZXAoMSwgbGVuZ3RoKG5mdW5jdGlvbnMpKQoKc3Vic2V0cyA8LSBuYW1lcyhmaXQkcG9zdGVyaW9yc1ssIC0xXSkKc3RpbSA8LSBzYXBwbHkoc3Ryc3BsaXQoc3Vic2V0cywgIi8iKSwgZnVuY3Rpb24oeCkgeFsxXSkKc3RpbW5hbWVzIDwtIHVuaXF1ZShzdGltKQpzdGltIDwtIGxhcHBseShzdGltbmFtZXMsIGZ1bmN0aW9uKHgpIHN1YnNldHNbc3RpbSAlaW4lIHhdKQpuYW1lcyhzdGltKSA8LSBzdGltbmFtZXMKcGFyZW50IDwtIHNhcHBseShzdHJzcGxpdChzdWJzZXRzLCAiLyIpLCBmdW5jdGlvbih4KSB4WzJdKQpwYXJlbnRuYW1lcyA8LSB1bmlxdWUocGFyZW50KQpwYXJlbnQgPC0gbGFwcGx5KHBhcmVudG5hbWVzLCBmdW5jdGlvbih4KSBzdWJzZXRzW3BhcmVudCAlaW4lIHhdKQpuYW1lcyhwYXJlbnQpIDwtIHBhcmVudG5hbWVzCnN0aW1wYXJlbnQgIDwtIHNhcHBseShzdHJzcGxpdChzdWJzZXRzLCAiLyIpLCBmdW5jdGlvbih4KSBwYXN0ZSh4WzE6Ml0sIGNvbGxhcHNlID0gIi8iKSkKc3RpbXBhcmVudG5hbWVzIDwtdW5pcXVlKHN0aW1wYXJlbnQpCnN0aW1wYXJlbnQgPC0gbGFwcGx5KHN0aW1wYXJlbnRuYW1lcywgZnVuY3Rpb24oeCkgc3Vic2V0c1tzdGltcGFyZW50ICVpbiUgeF0pCm5hbWVzKHN0aW1wYXJlbnQpIDwtIHN0aW1wYXJlbnRuYW1lcwoKaW5mZWN0aW9uIDwtIGhpdgppbmZlY3Rpb25baGl2ID09IDBdIDwtICJOT04tSU5GRUNURUQiCmluZmVjdGlvbltoaXYgPT0gMV0gPC0gIklORkVDVEVEIgppbmZlY3Rpb25baXMubmEoaGl2KV0gPC0gIlBMQUNFQk8iCnBsb3QoZml0LCB0eXBlID0gImJveHBsb3QiLCBncm91cHMgPSBzdGltLCB3ZWlnaHRzID0gd2VpZ2h0TGlzdCwgbmNvbCA9IDIsCiAgICAgdGFyZ2V0ID0gaW5mZWN0aW9uKQpwbG90KGZpdCwgdHlwZSA9ICJib3hwbG90IiwgZ3JvdXBzID0gcGFyZW50LCB3ZWlnaHRzID0gd2VpZ2h0TGlzdCwgbmNvbCA9IDIsCiAgICAgICAgICAgICAgICAgIHRhcmdldCA9IGluZmVjdGlvbikKcGxvdChmaXQsIHR5cGUgPSAiYm94cGxvdCIsIGdyb3VwcyA9IHN0aW1wYXJlbnQsIHdlaWdodHMgPSB3ZWlnaHRMaXN0LCBuY29sID0gMywgdGFyZ2V0ID0gaW5mZWN0aW9uKQpgYGAKCioqUmFuZG9tIGVmZmVjdCBtb2RlbCBmb3IgZGlmZmVybnQgdGhyZXNob2xkcyoqCmBgYHtyIFJhbmRvbSBFZmZlY3QgR3JhcGgsd2FybmluZz1GQUxTRX0KbG9hZCgiZGF0YSBhbmFseXNpcy9yZXN1bHRzL0hWVE5yYW5kMi5Sb2JqIikKZm9yKHRocmVzaG9sZCBpbiBjKDAuNSwgMC43NSwgMC44NSwgMC45LCAwLjk1LCAxKSkgewogIHJhbmRwbG90IDwtIHBsb3QocmFuZFN0YWJpbGl0eSwgZmlsbCA9IHJvY1Jlc3VsdHMkYXVjLAogICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSB0aHJlc2hvbGQpCiAgcHJpbnQocmFuZHBsb3QpCn0KYGBgCgoqKklzaW5nIG1vZGVsIGZvciBkaWZmZXJudCB0aHJlc2hvbGRzKioKYGBge3Isd2FybmluZz1GQUxTRX0KbG9hZCgiZGF0YSBhbmFseXNpcy9yZXN1bHRzL0hWVE5pc2luZzIuUm9iaiIpCmZvcih0aHJlc2hvbGQgaW4gYygwLjUsIDAuNzUsIDAuODUsIDAuOSwgMC45NSwgMSkpIHsKICBpc2luZ3Bsb3QgPC0gcGxvdChzdGFiaWxpdHksIGZpbGwgPSByb2NSZXN1bHRzJGF1YywgdGhyZXNob2xkID0gdGhyZXNob2xkKQogIHByaW50KGlzaW5ncGxvdCkKfQpgYGAKCg==